﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace MetaSharp.Transformation.Tests.Patterns
{
    public class SwitchTests
    {
        [Fact]
        public async Task CanSwitchToVariable()
        {
            var p = Pattern.And(
                Pattern.Variable("x", Pattern.Any()),
                Pattern.Switch("x", Pattern.Any()));
            var m = await Pattern.Match(p, 7);

            Assert.True(m.Matched);
        }

        [Fact]
        public async Task CanSwitchToArray()
        {
            var p = Pattern.And(
                Pattern.Variable("x", Pattern.Any()),
                Pattern.Switch("x", Pattern.Array()));

            var m = await Pattern.Match(p, new object[] { new object[0] });
            Assert.True(m.Matched);
        }

        [Fact]
        public async Task CanMatchSwitchedObjectEvenWhenEnumerable()
        {
            // x:any x(IEnumerable { })
            var p = Pattern.And(
                Pattern.Variable("x", Pattern.Any()),
                Pattern.Switch("x", Pattern.Object(typeof(IEnumerable))));
            var m = await Pattern.Match(p, new[] { new[] { 7, 11 } });

            Assert.True(m.Matched);
        }

        [Fact]
        public async Task VariablesUpScopeCanBeReferencedInSwitch()
        {
            // x:any y:any z:y(any -> x + y) -> z
            var p = Pattern.Production(
                Pattern.And(
                    Pattern.Variable("x", Pattern.Any()),
                    Pattern.Variable("y", Pattern.Any()),
                    Pattern.Variable("z", Pattern.Switch("y", Pattern.Production(Pattern.Any(), (int x, int y) => x + y)))),
                (int z) => z);
            var m = await Pattern.Match(p, 7, 11);

            Assert.Equal(18, m.Value);
        }

        [Fact]
        public void VariablesInSwitchDoNotCarryUpScope()
        {
            // x:any x(y:any) -> y
            var p = Pattern.Production(
                Pattern.And(
                        Pattern.Variable("x", Pattern.Any()),
                        Pattern.Switch("x", Pattern.Variable("y", Pattern.Any()))),
                (int y) => y);
            Pattern.Match(p, 7).WaitForThrow<KeyNotFoundException>();
        }
    }
}
